{
	let debug = false;

	function iVue(options) {
		this._init(options);
	}

	iVue.prototype._init = function(options) {
		let opts = options;
		this.$options = opts; // options 为上面使用时传入的结构体，包括el,data,methods
		this.$el = document.querySelector(opts.el); // el是 #app, this.$el是id为app的Element元素
		this.$data = opts.data; // this.$data = {number: 0}
		this.$methods = opts.methods; // this.$methods = {increment: function(){}}

		this._binding = {}; //_binding保存着model与view的映射关系，也就是我们前面定义的iWatcher的实例。当model改变时，我们会触发其中的指令类更新，保证view也能实时更新
		this._obverse(this.$data)
		this._complie(this.$el);
	}
	//使data上的属性添加getter/setter
	iVue.prototype._obverse = function(obj) { // obj = {number: 0}
		let value;
		for(key in obj) {
			if(obj.hasOwnProperty(key)) {
				this._binding[key] = {
					_directives: []
				};
				value = obj[key];
				if(typeof value === 'object') {
					this._obverse(value);
				}
				let binding = this._binding[key];
				let status = {
					enumerable: true,
					configurable: true,
					get() {
						if(debug) {
							console.log(`get ${value}`);
						}
						return value;
					},
					set(newVal) {
						if(debug) {
							console.log(`update ${newVal}`);
						}
						if(value !== newVal) {
							value = newVal;
							// 当number改变时，触发_binding[number]._directives 中的绑定的Watcher类的更新
							binding._directives.forEach(item => item.update());
						}
					}
				};
				Object.defineProperty(this.$data, key, status)
				Object.defineProperty(this, key, status)
			}
		}
	}
	//编译dom元素
	iVue.prototype._complie = function(root) { //root 为 id为app的Element元素，也就是我们的根元素
		let _this = this;
		let nodes = root.children;
		for(let i = 0; i < nodes.length; i++) {
			let node = nodes[i];
			if(node.children.length) { // 对所有元素进行遍历，并进行处理
				_this._complie(node);
			}
			if(node.hasAttribute('iv-click')) { // 如果有iv-click属性，我们监听它的onclick事件，触发increment事件，即number++
				let attrVal = node.getAttribute('iv-click');
				node.addEventListener('click', (function() {
					return _this.$methods[attrVal].bind(_this.$data); //bind是使data的作用域与method函数的作用域保持一致
				})());
			}
			if(node.hasAttribute('iv-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) { // 如果有iv-model属性，并且元素是INPUT或者TEXTAREA，我们监听它的input事件
				node.addEventListener('input', (function(key) {
					let attrVal = node.getAttribute('iv-model');
					//_this._binding['number']._directives = [一个iWatcher实例]
					// 其中iWatcher.prototype.update = function () {
					//    node['vaule'] = _this.$data['number'];  这就将node的值保持与number一致
					// }
					let watcher = new iWatcher('input', node, 'value', _this, attrVal);
					_this._binding[attrVal]._directives.push(watcher);
					return function() {
						let value = nodes[key].value;
						if(typeof _this.$data[attrVal] === "number") {
							value = parseFloat(value);
						}
						_this.$data[attrVal] = value; // 使number 的值与 node的value保持一致，已经实现了双向绑定
					}
				})(i));
			}
			if(node.hasAttribute('iv-bind')) { // 如果有v-bind属性，我们只要使node的值及时更新为data中number的值即可
				let attrVal = node.getAttribute('iv-bind');
				let watcher = new iWatcher('text', node, 'innerHTML', _this, attrVal);
				_this._binding[attrVal]._directives.push(watcher);
			}
		}
	}

	function iWatcher(name, el, attr, vm, exp) {
		this.name = name; //指令名称，例如文本节点，该值设为"text"
		this.el = el; //指令对应的DOM元素
		this.attr = attr; //绑定的属性值，本例为"innerHTML"
		this.vm = vm; //指令所属iVue实例
		this.exp = exp; //指令对应的值，本例如"number"
		this.update();
	}
	iWatcher.prototype.update = function() {
		//比如 H3.innerHTML = this.data.number; 当number改变时，会触发这个update函数，保证对应的DOM内容进行了更新。
		this.el[this.attr] = this.vm.$data[this.exp];
	}
	Window.iVue = iVue;
}